# coding=utf-8
import threading
import time

import allure
import jsonpath

from common.assert_operator import *
from common.db import *
from common.read_yaml import *
from common.utils import Utils

string_assert = string_assert() # 字符串校验类
pact = Pact() # 契约校验类
execute_sql = sql() # sql集合
utils = Utils()
data = ReadYaml_By_Root_Dict("case/99_outside_api_test/01_workflow_outside_test/99_01_5_MobileProcessInitiate_MobileProcessReInitiate.yml").get_yaml_data()  # 读取数据

@allure.feature('测试工作流外部接口：静默发起选人接口、重新发起接口')  # 测试报告显示测试功能
class Test_99_01_5_MobileProcessInitiate_MobileProcessReInitiate():
    """
    测试接口:
    /wf/Api/AutoInitiateProcess/MobileProcessInitiate
    /wf/Api/AutoInitiateProcess/MobileProcessReInitiate
    """
    # **************************静默发起选人接口正常场景****************************
    # 获取yml文件中[静默发起选人]的数据参数
    Params = data['静默发起选人']
    # 获取yml的title，并作为ids的值传给用例
    ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    def test_MobileProcessInitiate(self, user_login, title, param, expect):
        allure.dynamic.description(f"{param['用例描述']}")  # 动态解析用例描述在测试报告中展示
        user, ProcessModuleName, BusinessGUID, StepAuditors, OtherParams = param['用户'], param['流程模板'], \
                                                                           param['业务GUID'], param['步骤责任人'], \
                                                                           param['其他参数']
        main = user_login.goto_Outside_Api(user)  # 进入外部接口类
        ProcessInitiateAdapter_resp = main.ProcessInitiateAdapter_By_Module(user, ProcessModuleName, BusinessGUID,
                                                                            OtherParams=OtherParams)
        resp = main.MobileProcessInitiate_By_Module(user, ProcessModuleName, BusinessGUID,
                                                    ProcessInitiateAdapter_resp.json(),
                                                    StepAuditors, OtherParams)
        # 正常发起的契约格式
        contract_format = Matcher({
            "code": 0,
            "data": Matcher({
                "proc_id": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)", example="f97b340b-085f-587d-5874-39fdf94cd978"),
                "node_id": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)", example="8e670165-e291-dc8b-1198-39ff3da8f6d8"),
                "package_id": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)",
                                   example="88552455-9627-4e41-a5d3-a038767f2c10"),
                "parent_id": Term(r"\w{32}", example="60c72ad005d3e1452202121091406326", nullable=True)
            }),
            "message": expect['响应提示校验'],
            "errorinfo": expect['响应提示校验']
        })
        # 契约校验
        pact.pact_verify(contract_format, resp.json())
        # 获取流程GUID后，查询结果然后断言流程的数据库信息
        proc_id = jsonpath.jsonpath(resp.json(),"$.data['proc_id']")[0]
        sql = execute_sql.create_query_sql_by_id(proc_id)
        # 等待查询结果中步骤名称不等于分流
        utils.query_until_column_value_matched(sql, '步骤名称','!=','分流')
        # 等待查询结果中节点状态不等于0
        result = utils.query_until_column_value_matched(sql, '节点状态','!=','0')
        # 静默发起草稿流程时的断言。发起时有跳过，直到归档，需要判断后加等待
        if expect['数据校验'][1][1] == '结束':
            utils.query_until_column_value_matched(sql, '步骤名称', '==', '结束')
            # 断言发起的流程是预期保存的草稿。
            string_assert.eq(expect['流程GUID'], proc_id)
        # result = sqlserver_query_return_contain_field(sql)
        list_each_equal(expect['数据校验'],result)
        try:
            # 数据库校验附件同步
            wf_attachments = expect['附件校验']
            sql = f"""SELECT order_code '序号',name '附件名称' FROM wf_sys_attachment WITH (NOLOCK)
                        WHERE business_id='{BusinessGUID}'"""
            result = sqlserver_query_return_contain_field(sql)
            list_each_equal(wf_attachments,result)
        except:
            pass


    # **************************静默发起选人接口异常场景****************************
    # 获取yml文件中[静默发起选人_异常场景]的数据参数
    Params = data['静默发起选人_异常场景']
    # 获取yml的title，并作为ids的值传给用例
    ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    def test_MobileProcessInitiate_Abnormal(self, user_login, title, param, expect):
        allure.dynamic.description(f"{param['用例描述']}")  # 动态解析用例描述在测试报告中展示
        user, ProcessModuleName, BusinessGUID, StepAuditors, OtherParams = param['用户'], param['流程模板'], \
                                                                           param['业务GUID'], param['步骤责任人'], \
                                                                           param['其他参数']
        main = user_login.goto_Outside_Api(user)  # 进入外部接口类
        # 不在适配接口传入错误的参数，以免适配接口报错，无法验证发起接口。
        ProcessInitiateAdapter_resp = main.ProcessInitiateAdapter_By_Module(user, ProcessModuleName, BusinessGUID)
        resp = main.MobileProcessInitiate_By_Module(user, ProcessModuleName, BusinessGUID,
                                                    ProcessInitiateAdapter_resp.json(),
                                                    StepAuditors, OtherParams)
        # 发起失败的契约格式
        contract_format = Matcher({
            "code": -1,
            "data": None,
            "message": expect['响应提示校验'],
            "errorinfo": expect['响应提示校验']
        })
        # 契约校验
        pact.pact_verify(contract_format, resp.json())

    # **************************重新发起流程接口正常场景****************************
    # 获取yml文件中[重新发起流程]的数据参数
    Params = data['重新发起流程']
    # 获取yml的title，并作为ids的值传给用例
    ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    def test_MobileProcessReInitiate(self, user_login, title, param, expect):
        allure.dynamic.description(f"{param['用例描述']}")  # 动态解析用例描述在测试报告中展示
        user, ProcessModuleName, BusinessGUID, OtherParams = param['用户'], param['流程模板'], param['业务GUID'], param['其他参数']
        main = user_login.goto_Outside_Api(user)  # 进入外部接口类
        resp = main.MobileProcessReInitiate_By_Module(user, ProcessModuleName, BusinessGUID, OtherParams)
        # 重新发起契约格式
        contract_format = Matcher({
            "code": 0,
            "data": Matcher({
                "isOk": True,
                "canPass": 1,
                "branch": [],
                "actuals": [],
                "transitions": [],
                "stepStatus": "2",
                "isConfirmPath": False,
                "stepId": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)", example="f97b340b-085f-587d-5874-39fdf94cd978"),
                "passMessage": "",
                "validateResult": []
            }),
            "message": expect['响应提示校验'],
            "errorinfo": expect['响应提示校验']})

        # 重新发起，发起草稿
        create_contract_format = Matcher({
            "code": 0,
            "data": Matcher({
                "proc_id": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)", example="f97b340b-085f-587d-5874-39fdf94cd978"),
                "node_id": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)", example="8e670165-e291-dc8b-1198-39ff3da8f6d8"),
                "package_id": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)",
                                   example="88552455-9627-4e41-a5d3-a038767f2c10"),
                "parent_id": Term(r"\w{32}", example="60c72ad005d3e1452202121091406326", nullable=True)
            }),
            "message": expect['响应提示校验'],
            "errorinfo": expect['响应提示校验']
        })
        # 查询到此流程的流程GUID
        get_processGUID_sql = f"""SELECT id '流程GUID' FROM dbo.WfProcessInstance WHERE BusinessKey='{BusinessGUID}'"""
        proc_id = utils.get_column_value_by_two_array(sqlserver_query_return_contain_field(get_processGUID_sql),'流程GUID')[0]
        # 获取流程GUID后，查询结果然后断言流程的数据库信息
        sql = execute_sql.create_query_sql_by_id(proc_id)
        # 等待查询结果中节点状态不等于0，静默发起草稿流程时的断言。发起时有跳过，直到归档，需要判断后加等待
        result = utils.query_until_column_value_matched(sql, '节点状态', '!=', '0')
        # 契约校验，重新发起草稿和重新发起在途的响应不一样
        try:
            # 草稿流程，重新发时，校验是否发起的是原来的草稿。
            proc_id = expect['流程GUID']
            pact.pact_verify(create_contract_format, resp.json())
            # 断言发起的流程是预期保存的草稿。
            string_assert.eq(expect['流程GUID'], proc_id)
        except:
            pact.pact_verify(contract_format, resp.json())
        list_each_equal(expect['数据校验'], result)


    # **************************重新发起流程接口异常场景****************************
    # 获取yml文件中[重新发起流程_异常场景]的数据参数
    Params = data['重新发起流程_异常场景']
    # 获取yml的title，并作为ids的值传给用例
    ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    def test_MobileProcessReInitiate_Abnormal(self, user_login, title, param, expect):
        allure.dynamic.description(f"{param['用例描述']}")  # 动态解析用例描述在测试报告中展示
        user, ProcessModuleName, BusinessGUID, OtherParams = param['用户'], param['流程模板'], param['业务GUID'], param['其他参数']
        main = user_login.goto_Outside_Api(user)  # 进入外部接口类
        resp = main.MobileProcessReInitiate_By_Module(user, ProcessModuleName, BusinessGUID, OtherParams)
        # 发起失败的契约格式
        contract_format = Matcher({
            "code": -1,
            "data": None,
            "message": expect['响应提示校验'],
            "errorinfo": expect['响应提示校验']
        })
        # 契约校验
        pact.pact_verify(contract_format, resp.json())

    # # 获取yml文件中AutoInitiateProcess_Abnormal的数据参数
    # Params = data['AutoInitiateProcess_Abnormal']
    # # 获取yml的title，并作为ids的值传给用例
    # ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    # @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    # def test_AutoInitiateProcess_Abnormal(self, user_login, title, param, expect):
    #     allure.dynamic.description(f"{param['description']}")  # # 动态解析用例描述在测试报告中展示
    #     main = user_login.goto_Outside_Api(param['user'])    # 进入外部接口类
    #     resp = main.AutoInitiateProcess_By_Module(param['user'], param['ProcessModuleName'], param['BusinessGUID'],
    #                                                  OtherParams=param['OtherParams'])
    #     contract_format = Matcher({
    #         "code": -1,
    #         "data": None,
    #         "message": expect['response_tips'],
    #         "errorinfo": expect['response_tips']
    #     })
    #     pact.pact_verify(contract_format, resp.json())
    #
    # # **************************发起适配接口正常场景****************************
    # # 获取yml文件中ProcessInitiateAdapter的数据参数
    # Params = data['ProcessInitiateAdapter']
    # # 获取yml的title，并作为ids的值传给用例
    # ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    # @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    # def test_ProcessInitiateAdapter(self, user_login, title, param, expect):
    #     allure.dynamic.description(f"{param['description']}")  # # 动态解析用例描述在测试报告中展示
    #     main = user_login.goto_Outside_Api(param['user'])    # 进入外部接口类
    #     resp = main.ProcessInitiateAdapter_By_Module(param['user'], param['ProcessModuleName'], param['BusinessGUID'],
    #                                                  OtherParams=param['OtherParams'])
    #     dict_assert(expect['response'], resp.json())
    #
    # # **************************发起适配接口异常场景****************************
    # # 获取yml文件中ProcessInitiateAdapter_Abnormal的数据参数
    # Params = data['ProcessInitiateAdapter_Abnormal']
    # # 获取yml的title，并作为ids的值传给用例
    # ids_list = jsonpath.jsonpath(Params, "$[*][0]")
    # @pytest.mark.parametrize("title, param, expect", Params, ids=ids_list)
    # def test_ProcessInitiateAdapter_Abnormal(self, user_login, title, param, expect):
    #     allure.dynamic.description(f"{param['description']}")  # # 动态解析用例描述在测试报告中展示
    #     main = user_login.goto_Outside_Api(param['user'])    # 进入外部接口类
    #     resp = main.ProcessInitiateAdapter_By_Module(param['user'], param['ProcessModuleName'], param['BusinessGUID'],
    #                                                  OtherParams=param['OtherParams'])
    #     dict_assert(expect['response'], resp.json())
    #     # # 如果message等于【步骤及责任人明确，请使用静默发起接口！】，才可以静默发起。
    #     # if resp.json()['message'] != "步骤及责任人明确，请使用静默发起接口！":
    #     #     isAutoInitiate = 0
    #     # else:
    #     #     isAutoInitiate = 1
    #     # # 契约格式
    #     # contract_format = Matcher(
    #     #     {"code": 0,
    #     #         "data": Matcher({
    #     #             "isAutoInitiate": isAutoInitiate,
    #     #             "steps": EachLike({
    #     #                 "StepList": EachLike({
    #     #                     "StepName": Term(r"^.{1,100}$", example="开始"),
    #     #                     "StepType": Enum([0, 1, 2, 3]),
    #     #                     "NodeConfirm": Enum([0, 1]),
    #     #                     "Nodes": EachLike({
    #     #                         "AuditorName": Term(r"^.{3,20}$", example="系统管理员"),
    #     #                         "AuditorDepartMent": Term(r"^.{2,100}$", example="集团"),
    #     #                         "AuditorGuid": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)",
    #     #                                             example="4230BC6E-69E6-46A9-A39E-B929A06A84E8"),
    #     #                         "AuditorDepartMentGuid": Term(r"(\w+)-(\w+)-(\w+)-(\w+)-(\w+)",
    #     #                                                       example="11B11DB4-E907-4F1F-8835-B9DAAB6E1F23"),
    #     #                         "Checked": Enum([0, 1]),
    #     #                         "NodeGuid": Term(r"^.{7,36}$", example="new_start")
    #     #                     },minimum=0),
    #     #                     "CanAdjustAuditor": Enum([0, 1]),
    #     #                     "CanEmptyAuditor": Enum([0, 1])
    #     #                 })
    #     #             })
    #     #         }),
    #     #         "message": expect['response_tips'],
    #     #         "errorinfo": expect['response_tips']
    #     #     })
    #     # # 契约校验
    #     # pact.pact_verify(contract_format,resp.json())
